#include "hot.h"

HINSTANCE hInstance;

// ----------------------------------------------------------------------------------------------
// Paramblock2


enum { hot_params, };
enum { hot_resolution, hot_size, hot_windspeed, hot_waveheight, hot_shortestwave, hot_choppiness, hot_winddirection, hot_dampreflection, hot_windalign, hot_oceandepth, hot_time, hot_seed, hot_interpolation, hot_scale};

static ParamBlockDescID descVer0[] = {
	{ TYPE_FLOAT, NULL, TRUE, hot_resolution },
	{ TYPE_FLOAT, NULL, TRUE, hot_size },
	{ TYPE_FLOAT, NULL, TRUE, hot_windspeed },
	{ TYPE_FLOAT, NULL, TRUE, hot_waveheight },
	{ TYPE_FLOAT, NULL, TRUE, hot_shortestwave },
	{ TYPE_FLOAT, NULL, TRUE, hot_choppiness },
	{ TYPE_FLOAT, NULL, TRUE, hot_winddirection },
	{ TYPE_FLOAT, NULL, TRUE, hot_dampreflection },
	{ TYPE_FLOAT, NULL, TRUE, hot_windalign },
	{ TYPE_FLOAT, NULL, TRUE, hot_oceandepth },
	{ TYPE_FLOAT, NULL, TRUE, hot_time },
	{ TYPE_FLOAT, NULL, TRUE, hot_seed },
	{ TYPE_BOOL, NULL, TRUE, hot_interpolation}
};

static ParamVersionDesc versions[] =
{
	ParamVersionDesc(descVer0,13,0)
};

static ParamBlockDesc2 hot_param_blk ( hot_params, _T("Ocean Parameters"),  0, &hotDesc, P_AUTO_CONSTRUCT + P_AUTO_UI, SIMPMOD_PBLOCKREF, 
	//
	IDD_HOTPARAM, IDS_RB_PARAMETERS, 0, 0, NULL,
	//
	hot_resolution, _M("Resolution"), TYPE_FLOAT, P_ANIMATABLE, IDS_RESOLUTION,
		p_default, 8.0f,
		p_range, 4.0f, 500.0f,
		p_ui, TYPE_SPINNER, TYPE_FLOAT, IDC_RESOLUTION, IDC_RESOLUTIONSPN, 1.0f, end,
	//
	hot_size, _M("Size"), TYPE_FLOAT, P_ANIMATABLE, IDS_SIZE,
		p_default, 200.0f,
		p_range, 0.0f, 999999.0f,
		p_ui, TYPE_SPINNER, EDITTYPE_INT, IDC_SIZE, IDC_SIZESPN, 1.0f, end,
	//
	hot_windspeed, _M("Wind Speed"), TYPE_FLOAT, P_ANIMATABLE, IDS_WINDSPEED,
		p_default, 30.0f,
		p_range, 0.0f, 999999.0f,
		p_ui, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_WINDSPEED, IDC_WINDSPEEDSPN, 1.0f, end,
	//
	hot_waveheight, _M("Wave Height"), TYPE_FLOAT, P_ANIMATABLE, IDS_WAVEHEIGHT,
		p_default, 1.0f,
		p_range, 0.0001f, 100.0f,
		p_ui, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_WAVEHEIGHT, IDC_WAVEHEIGHTSPN, 0.01f, end,
	//
	hot_shortestwave, _M("Shortest Wave"), TYPE_FLOAT, P_ANIMATABLE, IDS_SHORTESTWAVE,
		p_default, 1.0f,
		p_range, 0.02f, 999999.0f,
		p_ui, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_SHORTESTWAVE, IDC_SHORTESTWAVESPN, 0.1f, end,
	//
	hot_choppiness, _M("Choppiness"), TYPE_FLOAT, P_ANIMATABLE, IDS_CHOPPINESS,
		p_default, 1.0f,
		p_range, 0.0f, 100.0f, p_ui, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_CHOPPINESS, IDC_CHOPPINESSSPN, 0.1f, end,
	//
	hot_winddirection, _M("Wind Direction"), TYPE_FLOAT, P_ANIMATABLE, IDS_WINDDIRECTION,
		p_default, 0.0f,
		p_range, 0.0f, 360.0f,
		p_ui, TYPE_SPINNER, EDITTYPE_INT, IDC_WINDDIRECTION, IDC_WINDDIRECTIONSPN, 1.0f, end,
	//
	hot_dampreflection, _M("Damp Reflection"), TYPE_FLOAT, P_ANIMATABLE, IDS_DAMPREFLECTION,
		p_default, 1.0f,
		p_range, 0.0f, 1.0f,
		p_ui, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_DAMPREFLECTION, IDC_DAMPREFLECTIONSPN, 0.01f, end,
	//
	hot_windalign, _M("Wind Align"), TYPE_FLOAT, P_ANIMATABLE, IDS_WINDALIGN,
		p_default, 2.0f,
		p_range, 1.0f, 10.0f,
		p_ui, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_WINDALIGN, IDC_WINDALIGNSPN, 0.01f, end,
	//
	hot_oceandepth, _M("Ocean Depth"), TYPE_FLOAT, P_ANIMATABLE, IDS_OCEANDEPTH,
		p_default, 200.0f,
		p_range, 0.01f, 3000.0f,
		p_ui, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_OCEANDEPTH, IDC_OCEANDEPTHSPN, 1.0f, end,
	//
	hot_time, _M("Time"), TYPE_FLOAT, P_ANIMATABLE, IDS_TIME,
		p_default, 0.0f,
		p_range, 0.0f, 999999.0f,
		p_ui, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_TIME, IDC_TIMESPN, 0.1f, end,
	//
	hot_seed, _M("Seed"), TYPE_FLOAT, P_ANIMATABLE, IDS_SEED,
		p_default, 0.0f,
		p_range, 0.0f, 999999.0f,
		p_ui, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_SEED, IDC_SEEDSPN, 1.0f, end,
	//
	//hot_scale, _M("Scale"), TYPE_FLOAT, P_ANIMATABLE, IDS_SCALE,
	//	p_default, 1.0f,
	//	p_range, 0.00001f, 10.0f,
	//	p_ui, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_SCALE, IDC_SCALESPN, 0.1f, end,
	//
	hot_interpolation, _M("Interpolation"), TYPE_BOOL, P_RESET_DEFAULT, IDC_INTERPOLATION,
		p_default, TRUE, 
		p_ui, TYPE_SINGLECHEKBOX, NULL, end, 

	end
	);

INT_PTR HotDlgProc::DlgProc(TimeValue t,IParamMap2 *map, HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
	return FALSE;
}

HotMod::HotMod() 
{
	rebuild = true;
	pblock2 = NULL;
	hotDesc.MakeAutoParamBlocks(this);
	assert(pblock2);
}

void HotMod::BeginEditParams( IObjParam *ip, ULONG flags,Animatable *prev )
{
	this->ip = ip ;
	SimpleMod::BeginEditParams(ip,flags,prev);
	hotDesc.BeginEditParams(ip,this,flags,prev);	
}
		
void HotMod::EndEditParams( IObjParam *ip, ULONG flags,Animatable *next )
{
	SimpleMod::EndEditParams(ip,flags,next);
	hotDesc.EndEditParams(ip,this,flags,next);
	rebuild = true;
}

IOResult HotMod::Load(ILoad *iload)
{
	Modifier::Load(iload);
	ParamBlock2PLCB* plcb = new ParamBlock2PLCB(versions, 1, &hot_param_blk, this, SIMPMOD_PBLOCKREF);
	iload->RegisterPostLoadCallback(plcb);
	
	return IO_OK;
}

RefTargetHandle HotMod::Clone(RemapDir& remap)
{	
	HotMod* newmod = new HotMod();	
	newmod->ReplaceReference(SIMPMOD_PBLOCKREF,remap.CloneRef(pblock2));
	newmod->SimpleModClone(this, remap);
	BaseClone(this, newmod, remap);
	return(newmod);
}

Interval HotMod::GetValidity(TimeValue t)
{
	float f;	
	Interval valid = FOREVER;
	pblock2->GetValue(hot_resolution,t,f,valid);
	pblock2->GetValue(hot_size,t,			f,valid);
	pblock2->GetValue(hot_windspeed,t,		f,valid);
	pblock2->GetValue(hot_waveheight,t,		f,valid);
	pblock2->GetValue(hot_shortestwave,t,	f,valid);
	pblock2->GetValue(hot_choppiness,t,		f,valid);
	pblock2->GetValue(hot_winddirection,t,	f,valid);
	pblock2->GetValue(hot_dampreflection,t,	f,valid);
	pblock2->GetValue(hot_windalign,t,		f,valid);
	pblock2->GetValue(hot_oceandepth,t,		f,valid);
	pblock2->GetValue(hot_time,t,			f,valid);
	pblock2->GetValue(hot_seed,t,			f,valid);
	return valid;
}

void HotMod::InvalidateUI()
{
	ParamID pid = pblock2->LastNotifyParamID();

	hot_param_blk.InvalidateUI(pid);

	if (pid != 10 && pid != 3 && pid != 5)
		rebuild = true;
}

// ------------------------------------------------------------------------------------------------------
// Deformer code
HotDeformer::HotDeformer()
{

}

HotDeformer::HotDeformer(Matrix3& tm, Matrix3& itm, drw::Ocean* _o, drw::OceanContext* _oc)
{
	transform = tm;
	invtransform = itm;
	ocean = _o;
	oceanContext = _oc;

}

Point3 HotDeformer::Map(int i, Point3 p)
{
	p = p * transform;
	
	drw::EvalData evaldata; 

	if (true)
		oceanContext->eval_xz(p.x, p.y, evaldata);
	else
		oceanContext->eval2_xz(p.x, p.y, evaldata);

	p.x += evaldata.disp[0];
	p.y += evaldata.disp[2];
	p.z += evaldata.disp[1];

	p = p * invtransform;

	return p;
}

Deformer& HotMod::GetDeformer(TimeValue t, ModContext &mc, Matrix3& tm, Matrix3& itm)
{
	float resolution;
	float size;
	float windSpeed;
	float waveHeigth;
	float shortestWave;
	float choppiness;
	float windDirection;
	float dampReflections;
	float windAlign;
	float oceanDepth;
	float time;
	float seed;

	static HotDeformer deformer;
	
	pblock2->GetValue(hot_resolution,t,		resolution,FOREVER);
	pblock2->GetValue(hot_size,t,			size,FOREVER);
	pblock2->GetValue(hot_windspeed,t,		windSpeed,FOREVER);
	pblock2->GetValue(hot_waveheight,t,		waveHeigth,FOREVER);
	pblock2->GetValue(hot_shortestwave,t,	shortestWave,FOREVER);
	pblock2->GetValue(hot_choppiness,t,		choppiness,FOREVER);
	pblock2->GetValue(hot_winddirection,t,	windDirection,FOREVER);
	pblock2->GetValue(hot_dampreflection,t,	dampReflections,FOREVER);
	pblock2->GetValue(hot_windalign,t,		windAlign,FOREVER);
	pblock2->GetValue(hot_oceandepth,t,		oceanDepth,FOREVER);
	pblock2->GetValue(hot_time,t,			time,FOREVER);
	pblock2->GetValue(hot_seed,t,			seed,FOREVER);

	if (rebuild)
    {
		//ocean = 0;
		//oceanContext = 0;

		//if (ocean)
		//	delete ocean;
		//if (oceanContext)
		//	delete oceanContext;

        ocean = new drw::Ocean(
			resolution,
			resolution,
			size/float(resolution),
			size/float(resolution),
			windSpeed,
			shortestWave,
			0.00001f,
			windDirection / 180.0f * 3.14159265358979323846,
			1.0f - dampReflections,
			windAlign,
			oceanDepth,
			seed
			);

        oceanScale = ocean->get_height_normalize_factor();
        oceanContext = ocean->new_context(true, (choppiness > 0), false, false);
		rebuild = false;
     }

    ocean->update(time, * oceanContext, true,(choppiness > 0), false, false, oceanScale * waveHeigth, choppiness);

	deformer = HotDeformer(tm, itm, ocean, oceanContext);

	deformer.interpolation = pblock2->GetInt(hot_interpolation, t);

	return deformer;
}

RefTargetHandle SimpleMod2::GetReference(int i) 
	{ 
	switch (i) {
		case 0: return tmControl;
		case 1: return posControl;
		case 2: return pblock2;
		default: return NULL;
		}
	}

void SimpleMod2::SetReference(int i, RefTargetHandle rtarg) 
	{ 
	switch (i) {
		case 0: tmControl = (Control*)rtarg; break;
		case 1: posControl = (Control*)rtarg; break;
		case 2: pblock2 = (IParamBlock2*)rtarg; break;
		}
	}

Animatable* SimpleMod2::SubAnim(int i) 
	{ 
	switch (i) {
		case 0: return posControl;
		case 1: return tmControl;
		case 2: return pblock2;			
		default: return NULL;
		}
	}

// ------------------------------------------------------------------------------------------------------
// Common plugin code

BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved) 
{	
	// Hang on to this DLL's instance handle.
	if( fdwReason == DLL_PROCESS_ATTACH )
	{
		hInstance = hinstDLL;
		DisableThreadLibraryCalls(hInstance);
	}

	return(TRUE);
}

__declspec( dllexport ) int LibNumberClasses()
{
	return 2;
}

__declspec( dllexport ) ClassDesc *LibClassDesc(int i)
{
	switch(i)
	{
		case 0: return GetHotModDesc();	
		default: return 0;
	}
}

__declspec( dllexport ) const TCHAR *LibDescription()
{
	return GetString(IDS_LIB_DESC);
}
__declspec( dllexport ) ULONG LibVersion()
{
	return VERSION_3DSMAX;
}